#ifndef NETBT_UTIL 
#define NETBT_UTIL

#include <string>
#include <stdarg.h>
#include "SocketUtil.h"

using std::string;
static const unsigned short myNetBiosPort = 8137;

typedef struct
{
  bool valid;
  std::string name;
  struct in_addr ip;
  int ttl;
  unsigned char nb_flags;
}name_t;

extern bool NeedSwap;

void sival(char *buf,int pos,uint32_t val);
void ssval(char *buf,int pos,uint16_t val);
uint32_t ival(const char *buf,int pos);
uint16_t sval(const char *buf,int pos);

void     object_byte_swap(void *obj,int size);
uint16_t uint16_t_byte_swap(uint16_t x);
uint32_t uint32_t_byte_swap(uint32_t x);

bool ip_equal(const struct in_addr *ip1, const struct in_addr* ip2);
/* these macros make access to the packet buffers easier. See also the
functions SSVAL() and SIVAL(). */
#define PVAL(buf,pos,type) (*((type *)(buf + pos)))
#define ISWP(x) (NeedSwap? uint32_byte_swap((uint32_t)x):(x))
#define SSWP(x) (NeedSwap? uint16_byte_swap((uint16_t)x):(x))

#define BSW(x) SSWP(x)
#define BSL(x) ISWP(x)

//set the value of type char, int, short to the memory in buf+pos
#define SCVAL(buf,pos,x) PVAL(buf,pos,char) = (x)
#define SIVAL(buf,pos,val) sival((char *)(buf),pos,val)
#define SSVAL(buf,pos,val) ssval((char *)(buf),pos,val)
//get the value of type char, int, short in buf+pos
#define CVAL(buf,pos) PVAL(buf,pos,char const)
#define IVAL(buf,pos) ival((const char *)(buf),pos)
#define SVAL(buf,pos) sval((const char *)buf,pos)

void Debug(int debug_level, const char *format_str, ...);

namespace NbtUtil
{
    void init();
/*************************************
find a pointer to a netbios name
**************************************/
    const char *name_ptr(const char *buf,int ofs);

/*************************************
extract a netbios name from a buf
*************************************/
    void name_extract(const char *buf,int ofs,char *name);

/****************************************************************************
true if two netbios names are equal
****************************************************************************/
    bool name_equal(const char *s1, const char *s2);
/****************************************************************************
interpret the weird netbios "name"
****************************************************************************/
    void name_interpret(const char *in,char *out);

/****************************************************************************
return the total storage length of a mangled name
****************************************************************************/
    int name_len(const char *s);

/****************************************************************************
mangle a name into netbios format
****************************************************************************/
    void name_mangle(char const *in,char *out);

/****************************************************************************
get the broadcast address for our address (troyer@saifr00.ateng.az.honeywell.com)
****************************************************************************/
    bool broadcast_ip(struct in_addr *if_ipaddr,
            struct in_addr *if_bcast);


/****************************************************************************
send a single packet to a port on another machine
****************************************************************************/
    bool send_packet(const char *buf,int len,struct in_addr *ip, int port,int type);

/****************************************************************************
receive a name message
****************************************************************************/
    bool receive_nmb(socket_t client, char *buffer, int bufsize, struct in_addr *ip_addr, int timeout);

/****************************************************************************
send a name message
****************************************************************************/
    //bool send_nmb(int fd,char *buffer);
/****************************************************************************
read data from the client. Maxtime is in 10ths of a sec
****************************************************************************/
    int read_max_data(int fd,char *buffer,
            int bufsize,struct in_addr *ipaddr,int maxtime);

/****************************************************************************
read from a socket
****************************************************************************/
    int read_socket(int fd,char *buf,int len, struct in_addr *ipaddr);

/****************************************************************************
write to a socket
****************************************************************************/
    int write_socket(int fd,char *buf,int len);

/****************************************************************************
show a nmb message
****************************************************************************/
    void show_nmb(const char *inbuf);

/****************************************************************************
word out the length of a nmb message
****************************************************************************/
    int nmb_len(const char *buf);
/*******************************************
    get the mac address of the
********************************************/
int get_macaddr(char *buf, int buflen);

/***********************************
 * get the local ip address and the broadcast ip
 * *************************************/
int get_ipaddr(struct sockaddr_in *ip_addr,
        struct sockaddr_in *bcast_addr);
};

#endif
//the format of the packet
/*
                   1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |        NAME_TRN_ID           | OPCODE  |   NM_FLAGS  | RCODE |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          QDCOUNT              |           ANCOUNT             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          NSCOUNT              |           ARCOUNT             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

     0   1   2   3   4
   +---+---+---+---+---+
   | R |    OPCODE     |
   +---+---+---+---+---+

   Symbol     Bit(s)   Description

   OPCODE        1-4   Operation specifier:
                         0 = query
                         5 = registration
                         6 = release
                         7 = WACK
                         9 = refresh

   R               0   RESPONSE flag:
                         if bit == 0 then request packet
                         if bit == 1 then response packet.

   The NM_FLAGS field is defined as:

     0   1   2   3   4   5   6
   +---+---+---+---+---+---+---+
   |AA |TC |RD |RA | 0 | 0 | B |
   +---+---+---+---+---+---+---+

   Symbol     Bit(s)   Description

   B               6   Broadcast Flag.
                         = 1: packet was broadcast or multicast
                         = 0: unicast
   RA              3   Recursion Available Flag.

                       Only valid in responses from a NetBIOS Name
                       Server -- must be zero in all other
                       responses.

                       If one (1) then the NBNS supports recursive
                       query, registration, and release.

                       If zero (0) then the end-node must iterate
                       for query and challenge for registration.

   RD              2   Recursion Desired Flag.

                       May only be set on a request to a NetBIOS
                       Name Server.

                       The NBNS will copy its state into the
                       response packet.

                       If one (1) the NBNS will iterate on the
                       query, registration, or release.

   TC              1   Truncation Flag.

                       Set if this message was truncated because the
                       datagram carrying it would be greater than
                       576 bytes in length.  Use TCP to get the
                       information from the NetBIOS Name Server.

   AA              0   Authoritative Answer flag.

                       Must be zero (0) if R flag of OPCODE is zero
                       (0).

                       If R flag is one (1) then if AA is one (1)
                       then the node responding is an authority for
                       the domain name.

                       End nodes responding to queries always set
                       this bit in responses.


*/

/*The Format of Requestion Packet
                    1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   /                         QUESTION_NAME                         /
   /                                                               /
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |         QUESTION_TYPE         |        QUESTION_CLASS         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 QUESTION_TYPE is defined as:

   Symbol      Value   Description:

   NB         0x0020   NetBIOS general Name Service Resource Record
   NBSTAT     0x0021   NetBIOS NODE STATUS Resource Record (See NODE
                       STATUS REQUEST)

   QUESTION_CLASS is defined as:

   Symbol      Value   Description:

   IN         0x0001   Internet class

*/
